home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / plotting / imagetoo / imagetl1.lha / Imagetool / HDF / df.c next >
Encoding:
C/C++ Source or Header  |  1990-09-20  |  46.3 KB  |  1,521 lines

  1. /*****************************************************************************
  2. *              NCSA HDF version 3.10
  3. *                July 1, 1990
  4. *
  5. * NCSA HDF Version 3.10 source code and documentation are in the public
  6. * domain.  Specifically, we give to the public domain all rights for future
  7. * licensing of the source code, all resale rights, and all publishing rights.
  8. * We ask, but do not require, that the following message be included in all
  9. * derived works:
  10. * Portions developed at the National Center for Supercomputing Applications at
  11. * the University of Illinois at Urbana-Champaign.
  12. * THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE
  13. * SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION,
  14. * WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE
  15. *****************************************************************************/
  16.  
  17. #ifdef RCSID
  18. static char RcsId[] = "@(#)$Revision: 3.4 $"
  19. #endif
  20. /*
  21. $Header: /pita/work/HDF/dev/RCS/src/df.c,v 3.4 90/06/29 10:07:31 mfolk beta $
  22. $Log:    df.c,v $
  23.  * Revision 3.4  90/06/29  10:07:31  mfolk
  24.  * *** empty log message ***
  25.  * 
  26.  * Revision 3.3  90/05/23  15:53:29  clow
  27.  * added MACRO "DF_OPENERR" to give uniform error open checking,
  28.  * especially for unbufferred I/O open
  29.  * 
  30. */
  31. /*-----------------------------------------------------------------------------
  32.  * File:    df.c
  33.  * Purpose: HDF low level file access
  34.  * Invokes: df.h
  35.  * Contents: 
  36.  *  DFImemcopy: copy bytes, on machines with no memcpy equivalents
  37.  *  DFopen: open HDF file
  38.  *  DFclose: close HDF file
  39.  *  DFIseedDDs: read data descriptors into memory
  40.  *  DFIcheck: check that dfile is a valid HDF file pointer
  41.  *  DFdescriptors: return a list of the data descriptors in the HDF file
  42.  *  DFnumber: count the number of occurrences of a given tag in the HDF file
  43.  *  DFsetfind: set up a search
  44.  *  DFfind: search for tag/ref combination
  45.  *  DFIfind: internal routine to actually perform search
  46.  *  DFIemptyDD: find an empty DD in the HDF file, or create one
  47.  *  DFaccess: set up a read/write on a data element
  48.  *  DFstart: set up a read/write on a data element
  49.  *  DFread: read a portion of a data element
  50.  *  DFseek: seek to new position within data element
  51.  *  DFwrite: write portion of a data element
  52.  *  DFupdate: write out updated DDs to HDF file
  53.  *  DFstat: provide status information about HDF file
  54.  *  DFgetelement: read an entire data element
  55.  *  DFputelement: write an entire data element
  56.  *  DFdup: create an additional descriptor for a data element
  57.  *  DFdel: delete a data element
  58.  *  DFnewref: Get an unused reference number
  59.  *  DFishdf: is this an HDF file?
  60.  *  DFerrno: return value of DFerror
  61.  *  DFIerr: close a file saving DFerror, return -1, for error handling.
  62.  * Remarks: These are the only routines which access HDF files directly
  63.  *---------------------------------------------------------------------------*/
  64.  
  65. #define DFMASTER
  66. #include "df.h"
  67.  
  68. #define CKMALLOC( x, ret) { if (!x) { DFerror = DFE_NOSPACE; return(ret); } }
  69.  
  70. #define CKSEEK(x,y,z, ret)  {  if (DF_SEEK( x,(long)y,z) <0) \
  71.                 {DFerror = DFE_SEEKERROR; return(ret); } }
  72.  
  73. #define CKSEEKEND(x,y,z, ret)   {  if (DF_SKEND( x,(long)y,z) <0) \
  74.                 {DFerror = DFE_SEEKERROR; return(ret); } }
  75.  
  76. #ifdef VMS
  77. #define CKREAD(x,y,z,f, ret)    { \
  78.                 int32 currfileposn; \
  79.                 currfileposn = DF_TELL(f); \
  80.                 if (DF_READ( (char*)x, (int)(y), (int)(z), (f))<0) \
  81.                 { DFerror = DFE_READERROR; return(ret); } \
  82.                 DF_SEEK(f, (long) (currfileposn + y*z), 0); \
  83.                 }
  84. #else /*VMS*/
  85. #define CKREAD(x,y,z,f, ret)    { \
  86.                 if (DF_READ( (char*)x, (int)(y), (int)(z), (f))<0) \
  87.                 { DFerror = DFE_READERROR; return(ret); } \
  88.                 }
  89. #endif /*VMS*/
  90.  
  91. #define CKWRITE(x,y,z,f, ret)   { if (DF_WRITE( (char*)x, (int)y, (int)z,f)<0) \
  92.                 {DFerror = DFE_WRITEERROR; return(ret); } }
  93.  
  94. /*
  95.  *  Important Internal Variables
  96.  */
  97. static DF *DFlist=NULL;        /* pointer to list of open DFs */
  98. static int DFinuse=0;        /* How many are currently in use */
  99. static uint16 DFmaxref;        /* which is the largest ref used? */
  100. static unsigned char *DFreflist=NULL; /* list of refs in use */
  101. static char patterns[] = {0x80, 0x40, 0x20, 0x10, 0x08,
  102.                        0x04, 0x02, 0x01};
  103.  
  104. #ifdef MAC
  105.  
  106. /*
  107. *  Macintosh file stubs for HDF
  108. *
  109. *  Implement a subset of the C unbuffered file I/O stubs in the
  110. *  Mac toolbox.
  111. */
  112.  
  113.  
  114. static int hdfc = 'Puf2', hdft = '_HDF';
  115.  
  116. mopen(name, flags)
  117.     char *name;
  118.     int flags;
  119. {
  120.     short volref,rn;
  121.  
  122.     GetVol(NULL,&volref);
  123.     
  124.     if (flags & O_CREAT)                     /* we need to create it */
  125.         create(name, volref, hdfc, hdft);
  126.     
  127.     if (0 != fsopen(name, volref, &rn))
  128.         return(-1);
  129.         
  130.     return(rn);
  131. }
  132.  
  133. mclose(rn)
  134.     int rn;
  135. {
  136.     return(FSClose(rn));
  137.  
  138. }
  139.  
  140. mread(rn, buf, n)
  141.     int rn,n;
  142.     char *buf;
  143. {
  144.     if (0 != FSRead( rn, &n, buf))
  145.         return(-1);
  146.         
  147.     return(n);
  148.  
  149. }
  150.  
  151. mwrite(rn, buf, n)
  152.     int rn,n;
  153.     char *buf;
  154. {
  155.     if (0 != FSWrite( rn, &n, buf))
  156.         return(-1);
  157.         
  158.     return(n);
  159. }
  160.  
  161. mlseek(rn, n, m)
  162.     int rn,n,m;
  163. {
  164.     switch(m) {
  165.         case 0:
  166.         default:
  167.             m = 1;
  168.             break;
  169.         case 1:
  170.             m = 3;
  171.             break;
  172.         case 2:
  173.             m = 2;
  174.             break;
  175.     }
  176.     
  177.     if (0 != SetFPos(rn, m, n))
  178.         return(-1);
  179.         
  180.     if (0 != GetFPos(rn, &n))
  181.         return(-1);
  182.         
  183.     return(n);
  184. }
  185. #endif /* MAC */
  186.  
  187. /*-----------------------------------------------------------------------------
  188.  * Name:    DFImemcopy
  189.  * Purpose: Copy bytes from one place to another
  190.  * Inputs:  from, to: source and destination for copy
  191.  *          length: number of bytes to copy
  192.  * Returns: 0 on success, -1 on failure with DFerror set
  193.  * Users:   HDF systems programmers, on machines without memcpy equivalents
  194.  * Remarks: assumes non-overlapping
  195.  *          Intended for machines on which memcppy etc. do not work
  196.  *---------------------------------------------------------------------------*/
  197.  
  198. DFImemcopy( from, to, length)
  199. char *from, *to;
  200. register int length;
  201. {
  202.     length++;
  203.     while (--length) *to++ = *from++;
  204.     return(0);
  205. }
  206.  
  207. /*-----------------------------------------------------------------------------
  208.  * Name:    DFopen
  209.  * Purpose: open DF file if it exists, else create it if write access
  210.  * Inputs:  name: name of file to open
  211.  *          access: DFACC_READ, DFACC_WRITE, DFACC_CREATE, DFACC_ALL
  212.  *          ndds: number of dds in a block
  213.  * Returns: DF ptr to open file on success, NULL on failure with DFerror set
  214.  * Invokes: DFIseedDDs 
  215.  * Users:   HDF programmers, many HDF user-level routines, utilities
  216.  * Remarks: Contains hooks for multiple DF files open simultaneously
  217.  *---------------------------------------------------------------------------*/
  218.  
  219. DF *DFopen( name, access, ndds )
  220. char *name;
  221. int access;
  222. int ndds;
  223. {
  224.     int created, i;             /* created is true if file is newly created */
  225.  
  226.                     /* error checking */
  227.     DFerror = DFE_NOERROR;
  228.  
  229.     if (!(*name)) {                             /* check name */
  230.         DFerror = DFE_BADNAME;
  231.         return(NULL);
  232.     }
  233.  
  234.     if ((access & (DFACC_ALL))!= access || access==0) {     /* check access */
  235.         DFerror = DFE_BADACC;
  236.         return(NULL); 
  237.     }
  238.     
  239.     if (DFinuse >= DF_MAXDFS) {    /* is DF table filled up? */
  240.         DFerror = DFE_TOOMANY; 
  241.         return(NULL);  
  242.     }
  243.     
  244.                 /* open file, set it up */
  245.         /* set up space for list of DFs */
  246.     if (!DFlist) {
  247.         DFlist = (DF *) DFIgetspace(DF_MAXDFS * sizeof(DF));
  248.         for (i=0; i<DF_MAXDFS; i++)
  249.             DFlist[i].type = 0;    /* mark free */
  250.     }
  251.  
  252.         /* locate unused slot in table */
  253.     for (i=0; i<DF_MAXDFS && DFlist[ i].type != 0; i++);
  254.  
  255.     if ( i>=DF_MAXDFS) {                            /* no free slot */
  256.         DFerror = DFE_TOOMANY;
  257.         return(NULL); 
  258.     }
  259.  
  260.     if (access == DFACC_CREATE) {
  261.         created = 1;
  262.         access = DFACC_WRITE;                   /* equivalent to write */
  263.     }
  264.     else created = 0;
  265.  
  266.         /* does an extra open just to check if file exists */
  267.     if (created || DF_OPENERR(DFlist[i].file = DF_OPEN(name, DF_RDACCESS))) {
  268.         if (access<2) {         /* file does not exist, check if read access */
  269.             DFerror = DFE_FNF;  /* file not found */
  270.             return(NULL);
  271.         }
  272. #ifndef MAC
  273.         close (DF_CREAT( name, 0666));  /* else create the file */
  274. #else /* MAC */
  275.         DF_CLOSE(DF_CREAT(name, 0666));
  276. #endif 
  277.         created=1;
  278.     }
  279.     else
  280.         DF_CLOSE(DFlist[i].file);   /* open successful, close it */
  281.  
  282.         /* open file with correct access mode */
  283.     if ( DF_OPENERR(DFlist[i].file = DF_OPEN( name, 
  284.         ((access>1) ? DF_WRACCESS : DF_RDACCESS ))) ) {
  285.         DFerror = DFE_BADOPEN;
  286.         return(NULL);
  287.     }
  288.  
  289.     if (created) {      /* Create a DDH and DD's for a new file */
  290.         DFdd dd;
  291.         DFddh ddh;
  292.     char magick[4];
  293.         int j;
  294.  
  295.     strncpy(magick, DF_MAGICK, 4); /* magick number */
  296.         CKWRITE( magick,4,1,DFlist[i].file, NULL);
  297.  
  298.         ddh.next=0;                         /* only one DDH */
  299.         if (ndds<=0) DFlist[i].defdds = DF_DEFAULTDDS;  
  300.         else DFlist[i].defdds = ndds;       /* set up number of DDs in block */
  301.         ddh.dds = DFlist[i].defdds;
  302.         dd.tag=DFTAG_NULL;              /* set up empty DD */
  303.         dd.ref=0;                       /* offset, length don't care */
  304.  
  305. #ifdef DF_STRUCTOK                      /* okay to write structures? */
  306.         CKWRITE( &ddh, sizeof(DFddh), 1, DFlist[i].file, NULL); /* write it */
  307. #else /*DF_STRUCTOK*/
  308.         {
  309.             register char *p;
  310.             /* copy structure into buffer, write it out */
  311.             p = DFtbuf;
  312.             INT16WRITE( p, ddh.dds);    /* header */
  313.             INT32WRITE( p, ddh.next);
  314.             CKWRITE( DFtbuf, 6, 1, DFlist[i].file, NULL);   /* 6=header size */
  315.         }
  316. #endif /*DF_STRUCTOK*/
  317.  
  318.         for (j=0; j<ddh.dds; j++) {             /* write out DDs */
  319. #ifdef DF_STRUCTOK
  320.             CKWRITE( &dd, sizeof(DFdd),1, DFlist[i].file, NULL);
  321. #else /*DF_STRUCTOK*/
  322.             {
  323.                 register char *p;
  324.                 p = DFtbuf;
  325.                 UINT16WRITE( p, dd.tag);
  326.                 UINT16WRITE( p, dd.ref);
  327.                 INT32WRITE( p, dd.offset);
  328.                 INT32WRITE( p, dd.length);
  329.                 CKWRITE( DFtbuf, 12, 1, DFlist[i].file, NULL); /* 12=DD size */
  330.             }
  331. #endif /*DF_STRUCTOK*/
  332.         }
  333.     }
  334.     else {            /* if file already exists */
  335.          char magick[4];
  336.  
  337.         CKREAD( magick, 4, 1, DFlist[i].file, NULL); /* check magick number */
  338.         if ( strncmp(magick,DF_MAGICK,4)) {
  339.             DFerror = DFE_NOTDFFILE;
  340.             DF_CLOSE(DFlist[i].file);
  341.             return(NULL);
  342.         }
  343.     }
  344.  
  345.     /* store status information in struct */
  346.     if (ndds<=0) DFlist[i].defdds = DF_DEFAULTDDS;  
  347.     else DFlist[i].defdds = ndds;
  348.     DFlist[i].access=access;
  349.     DFlist[i].list = NULL;
  350.     DFlist[i].changed=0;
  351.     DFlist[i].last_tag= 0;
  352.     DFlist[i].last_ref= 0;
  353.     DFlist[i].type=1;
  354.     DFlist[i].up_access=0;
  355.     DFlist[i].up_dd = NULL;
  356.  
  357.             /* read DDs and store the information in internal structure */
  358.     if (DFIseedDDs( &DFlist[i]) <0) return(NULL);
  359.  
  360.     if (created) {                  /* create MT if new file */
  361.         DFdd *dd;
  362.         dd = &(DFlist[i].list->next->dd[0]);    /* first dd is in 2nd dle */
  363.         dd->tag = DFTAG_MT;
  364.         dd->ref = DF_MT;
  365.         dd->offset = 0;
  366.         dd->length = 0;
  367.     }
  368.     DFinuse++;                      /* no of DF slots in use */
  369.     return( &DFlist[i]);            /* DF file pointer */
  370. }
  371.  
  372.  
  373. /*-----------------------------------------------------------------------------
  374.  * Name:    DFclose
  375.  * Purpose: Write out updated DDs, close DF file
  376.  * Inputs:  dfile: pointer to open DF file
  377.  * Returns: 0 on success, -1 on failure with DFerror set
  378.  * Invokes: DFIcheck
  379.  * Users:   HDF programmers, many HDF user-level routines, utilities
  380.  *---------------------------------------------------------------------------*/
  381.  
  382. int DFclose( dfile)
  383. DF *dfile;
  384. {
  385.     DFdle *prev, *current;          /* DLEs being written out */
  386.     int i;
  387.  
  388.     DFerror = DFE_NOERROR;
  389.  
  390.     if ( DFIcheck(dfile))           /* is dfile a valid pointer? */
  391.         return(-1);
  392.  
  393.     if (dfile->type!=1) {           /* 0 is a closed file  or unused slot */
  394.         DFerror= DFE_NOTOPEN;
  395.         return(-1);
  396.     }
  397.  
  398.     prev=dfile->list;               /* start of DLE list */
  399.  
  400.     while (current=prev->next) {        /* for all DLEs */
  401.         if (dfile->changed) {           /* if file modified, write it out */
  402.                 /* current DD should be written at location prev->ddh.next */
  403.             CKSEEK( dfile->file, (long) prev->ddh.next,0, -1);
  404.             if (current->ddh.dds) {     /* if any DDs to write out */
  405. #ifdef DF_STRUCTOK
  406.                 CKWRITE( ¤t->ddh, sizeof(DFddh)+
  407.                     current->ddh.dds*sizeof(DFdd), 1, dfile->file, -1);
  408. #else /*DF_STRUCTOK*/
  409.                 {           /* write out dd struct elements */
  410.                     register  char *p;
  411.                     p = DFtbuf;
  412.                     INT16WRITE( p, current->ddh.dds);
  413.                     INT32WRITE( p, current->ddh.next);
  414.                     for (i=0; i<current->ddh.dds; i++) {
  415.                         UINT16WRITE( p, current->dd[i].tag);
  416.                         UINT16WRITE( p, current->dd[i].ref);
  417.                         INT32WRITE( p, current->dd[i].offset);
  418.                         INT32WRITE( p, current->dd[i].length);
  419.                     }
  420.                     CKWRITE( DFtbuf, 6+i*12, 1, dfile->file, -1);
  421.                             /* 6=size of DDH, 12=size of DD */
  422.                 }
  423. #endif /*DF_STRUCTOK*/
  424.             }
  425.         }
  426.         DFIfreespace((char*)prev);
  427.         prev=current;
  428.     }
  429.     DFIfreespace((char*)prev); /* get rid of the last one */
  430.  
  431.     if ( (DF_CLOSE( dfile->file)) !=0) {
  432.         DFerror = DFE_CANTCLOSE;
  433.         return(-1);
  434.     }
  435.  
  436.                     /* reset structure values */
  437.     dfile->last_ref= 0;
  438.     dfile->last_tag= 0;
  439.     dfile->type=0;
  440.     dfile->access=0;
  441.     dfile->file= 0;
  442.     dfile->list= (DFdle *) 0L;
  443.     DFinuse--;
  444.     return(0);
  445. }   
  446.  
  447.  
  448. /*-----------------------------------------------------------------------------
  449.  * Name:    DFIseedDDs
  450.  * Purpose: read DDs in file into memory
  451.  * Inputs:  dfile: pointer to open DF file
  452.  * Returns: 0 on success, -1 on failure with DFerror set
  453.  * Users:   HDF systems programmers, DFopen
  454.  *---------------------------------------------------------------------------*/
  455.  
  456. int DFIseedDDs(dfile)
  457. DF *dfile;
  458. {
  459.     DFdle *list;
  460.     DFddh ddh;
  461.     int i,n;                        /* n = no. of DDs in block */
  462.     
  463.     DFerror = DFE_NOERROR;
  464.  
  465.     if (dfile->list) {
  466.         DFerror = DFE_SEEDTWICE;    /* ### NOTE: Internal error! */
  467.         return(-1);
  468.     }
  469.     
  470.     dfile->list= (DFdle *) DFIgetspace(sizeof(DFdle));
  471.     /* includes one DD - unused */
  472.     CKMALLOC( dfile->list, -1);
  473.  
  474.     list=dfile->list;
  475.     list->next=NULL;                /* No other lists (yet) */
  476.     list->ddh.next= (int32)4L;      /* next is at 4 in file */
  477.     list->ddh.dds= -1;              /* flag so this is not written */
  478.  
  479.     DFmaxref = 0;                   /* largest ref found till now is 0 */
  480.  
  481.     while (list->ddh.next) {        /* while more headers to read */
  482.         CKSEEK( dfile->file, list->ddh.next, 0, -1);
  483.  
  484.                             /* read headers */
  485. #ifdef DF_STRUCTOK
  486.         CKREAD( &ddh, sizeof(DFddh), 1, dfile->file, -1);
  487. #else /*DF_STRUCTOK*/
  488.         {
  489.             register  char *p;
  490.             p = DFtbuf;
  491.             CKREAD( DFtbuf, 6, 1, dfile->file, -1);     /* 6 = size of header */
  492.             INT16READ( p, ddh.dds);
  493.             INT32READ( p, ddh.next);
  494.         }
  495. #endif /*DF_STRUCTOK*/
  496.         n   =ddh.dds;
  497.  
  498.     /* read in DDs */
  499.         list->next= (DFdle *)
  500.         DFIgetspace((unsigned)
  501.             (sizeof(DFdle)+ (n-1)* sizeof(DFdd)));
  502.                 /* note space for 1 DD included in DLE */
  503.         CKMALLOC( list->next, -1);
  504.         list=list->next;
  505.         list->next=NULL;
  506.     
  507.         DFmovmem((char*)&ddh, (char*)&(list->ddh),
  508.          sizeof(DFddh) ); /* Copy ddh */
  509.  
  510.         if (n) {
  511. #ifdef DF_STRUCTOK
  512.             CKREAD( &list->dd[0], sizeof(DFdd), n, dfile->file, -1);
  513.         /* load DD's */
  514. #else /*DF_STRUCTOK*/
  515.             {
  516.                 register  char *p;
  517.                 p = DFtbuf;
  518.                 CKREAD( DFtbuf, n*12, 1, dfile->file, -1);  /* 12=size of DD */
  519.                 for (i=0; i<n; i++) {
  520.                     UINT16READ( p, list->dd[i].tag);
  521.                     UINT16READ( p, list->dd[i].ref);
  522.                     INT32READ( p, list->dd[i].offset);
  523.                     INT32READ( p, list->dd[i].length);
  524.                 }
  525.             }
  526. #endif /*DF_STRUCTOK*/
  527.         }
  528.                 /* Remember highest ref found - ignore MTs */
  529.         for (i=0; i<n; i++)
  530.             if ((list->dd[i].ref > DFmaxref) && (list->dd[i].tag != DFTAG_MT))
  531.                                      DFmaxref = list->dd[i].ref;
  532.     }
  533.     return(0);
  534. }
  535.  
  536.  
  537. /*-----------------------------------------------------------------------------
  538.  * Name:    DFIcheck
  539.  * Purpose: check if dfile argument represents a valid DF file
  540.  * Inputs:  dfile: pointer to open DF file
  541.  * Returns: 0 on success, -1 on failure with DFerror set
  542.  * Users:   HDF systems programmers, several routines in this file
  543.  *---------------------------------------------------------------------------*/
  544.  
  545. int DFIcheck( dfile)
  546. DF *dfile;
  547. {
  548.     DFerror = DFE_NOERROR;
  549.     
  550.     if (!dfile) {
  551.         DFerror = DFE_DFNULL;
  552.         return(-1);
  553.         }
  554.  
  555.     if ((dfile->access & DFACC_ALL) != dfile->access)
  556.         DFerror = DFE_BADACC;
  557.  
  558.     if ((dfile->type >1) || (dfile->type <-1))
  559.         DFerror = DFE_ILLTYPE;
  560.  
  561.     if (!dfile->list)
  562.         DFerror= DFE_BADDDLIST;
  563.  
  564.     if (DFerror)
  565.         return(-1);
  566.     else
  567.         return(0);
  568.  
  569. }
  570.  
  571.  
  572. /*-----------------------------------------------------------------------------
  573.  * Name:    DFdescriptors
  574.  * Purpose: return a list of all the DDs in the file
  575.  * Inputs:  dfile: pointer to open DF file
  576.  *          ptr: pointer to space for the list of DDs
  577.  *          begin, num: the list starts at DD numbered begin, and contains
  578.  *              a maximum of num entries
  579.  * Returns: number of DDs returned in the list
  580.  * Invokes: DFIcheck
  581.  * Users:   HDF programmers, other routines and utilities
  582.  *---------------------------------------------------------------------------*/
  583.  
  584. int DFdescriptors(dfile, ptr, begin, num)
  585. DF *dfile;
  586. DFdesc ptr[];
  587. int begin, num;
  588. {
  589.     DFdle *DLEp;
  590.     int i,ddnum=0;
  591.  
  592.     if ( DFIcheck(dfile))
  593.         return(-1);
  594.     
  595.     if (begin<0) begin = 0;
  596.     if (num<0) num = 0;
  597.     ddnum = 0;
  598.     for (DLEp=dfile->list; DLEp; DLEp=DLEp->next)
  599.         for (i=0; i<DLEp->ddh.dds; i++, ddnum++)
  600.             if (ddnum>=begin) {
  601.                 if (ddnum<begin+num) {
  602.                     ptr[ddnum-begin] = DLEp->dd[i];
  603.                 }
  604.                 else
  605.                     return(num);
  606.             }
  607.     return(ddnum-begin);
  608. }
  609.  
  610.  
  611. /*-----------------------------------------------------------------------------
  612.  * Name:    DFnumber
  613.  * Purpose: return the number of occurrences of the given tag in the HDF file
  614.  * Inputs:  dfile: pointer to open DF file
  615.  *          tag: tag to count occurrences of
  616.  * Returns: number of occurrences of tag in file, -1 on error with DFerror set
  617.  *          if tag is DFTAG_WILDCARD, count occurrences of all tags
  618.  * Invokes: DFIcheck
  619.  * Users:   HDF programmers, other routines and utilities
  620.  *---------------------------------------------------------------------------*/
  621.  
  622. int DFnumber(dfile, tag)
  623. DF *dfile;
  624. uint16 tag;
  625. {
  626.     DFdle *DLEp;
  627.     int i, ntag=0;
  628.  
  629.     if ( DFIcheck(dfile))
  630.         return(-1);
  631.     
  632.     for (DLEp=dfile->list; DLEp; DLEp=DLEp->next)
  633.         if (tag==DFTAG_WILDCARD) ntag += DLEp->ddh.dds;
  634.         else {
  635.             for (i=0; i<DLEp->ddh.dds; i++)
  636.                 if (DLEp->dd[i].tag == tag) ntag++;
  637.         }
  638.  
  639.     return(ntag);
  640. }
  641.  
  642.  
  643. /*-----------------------------------------------------------------------------
  644.  * Name:    DFsetfind
  645.  * Purpose: set up parameters for a wildcard find
  646.  * Inputs:  dfile: pointer to open DF file
  647.  *          tag, ref: tag and ref of element to search for, 0 is wildcard
  648.  * Returns: 0 on success, -1 on failure
  649.  * Invokes: DFIcheck
  650.  * Users:   HDF programmers, several utilities
  651.  *---------------------------------------------------------------------------*/
  652.  
  653. int DFsetfind( dfile, tag, ref)
  654. DF *dfile;
  655. uint16 tag,ref;
  656. {
  657.  
  658.     if ( DFIcheck(dfile))
  659.         return(-1);
  660.     
  661.         /* remember tag, ref for subsequent searches */
  662.     dfile->last_tag=tag;
  663.     dfile->last_ref=ref;
  664.     dfile->last_dle=NULL;           /* flag value: nothing found so far */
  665.  
  666.     return(0);
  667. }
  668.     
  669.  
  670. /*-----------------------------------------------------------------------------
  671.  * Name:    DFfind
  672.  * Purpose: perform wildcard searches - sets up parameters, calls DFIfind
  673.  * Inputs:  dfile: pointer to open DF file
  674.  *          ptr: ptr to put in DD when found
  675.  * Returns: 0 on success, -1 on failure
  676.  *          if success, DD matching specification is copied to *ptr
  677.  * Invokes: DFIcheck, DFIfind
  678.  * Users:   HDF programmers, several utilities
  679.  *---------------------------------------------------------------------------*/
  680.  
  681. int DFfind(dfile, ptr)
  682. DF *dfile;
  683. DFdesc *ptr;
  684. {
  685.     DFdle *cDLEp;
  686.     int cdd;
  687.     uint16 tag, ref, ltag,lref;
  688.     int isfirst=1;
  689.  
  690.     if ( DFIcheck(dfile))
  691.         return(-1);
  692.  
  693.     DFerror = DFE_NOERROR;
  694.  
  695.     tag = dfile->last_tag;          /* tag, ref being searched for */
  696.     ref = dfile->last_ref;
  697.  
  698.     if (dfile->last_dle) {          /* something found previously */
  699.         isfirst = 0;
  700.         ltag= dfile->last_dle->dd[ dfile->last_dd ].tag;    /* prev tag, ref */
  701.         lref= dfile->last_dle->dd[ dfile->last_dd ].ref;
  702.     } else {
  703.     ltag = lref = 0;
  704.     }
  705.  
  706.     if ((tag!=DFTAG_NULL) &&        /* empty DDs are invisible on finds */
  707.         !DFIfind( dfile, tag, ref, isfirst, ltag, lref, &cDLEp, &cdd)) {
  708.         *ptr = cDLEp->dd[cdd];      /* if found, copy dd to ptr */
  709.         dfile->last_dd = cdd;       /* set last_dle and last_dd to DD found */
  710.         dfile->last_dle= cDLEp;
  711.         return(0);
  712.     } else {
  713.         DFerror = DFE_NOMATCH;
  714.         ptr->tag = 0;
  715.         ptr->ref = 0;
  716.         return(-1);
  717.     }
  718. }
  719.         
  720.  
  721. /*-----------------------------------------------------------------------------
  722.  * Name:    DFIfind
  723.  * Purpose: perform wildcard searches
  724.  * Inputs:  dfile: pointer to open DF file
  725.  *          tag, ref: tag, ref (possibly wildcard) being searched for
  726.  *          isfirst: 1 if first call to DFIfind for this tag/ref, else 0
  727.  *          ltag, lref: last tag and ref returned for this search,
  728.  *              don't care if isfirst set
  729.  *          cDLEp, cddp: pointers to DLE and DD number to return matched DD in
  730.  * Returns: 0 on success, -1 on failure
  731.  *          if success, cDLEp and cddp are set to point to matched DD
  732.  * Users:   HDF system programmers, DFfind, HDF utilities, many routines
  733.  * Remarks: The searching algorithm is a little complex.  It returns entries
  734.  *          in the sorting order of refs, then tags.  Even after a candidate
  735.  *          is found, searching continues till best candidate found.  Best way
  736.  *          to check if conditions: work it out independently for yourself!
  737.  *---------------------------------------------------------------------------*/
  738.  
  739. int DFIfind( dfile, tag, ref, isfirst, ltag, lref, cDLEp, cddp)
  740. DF *dfile;
  741. DFdle **cDLEp;
  742. int *cddp;
  743. int isfirst;                            /* 1 if no prev search, 0 otherwise */
  744. uint16 tag, ref, ltag, lref;
  745. {
  746.     DFdle *DLEp;
  747.     int i, found=0;
  748.     uint16 ctag=0, cref=0, wtag,wref; /* ctag, cref: tag, ref found so far */
  749.                                       /* wtag, wref: tag, ref being checked */
  750.  
  751.     DLEp=dfile->list;               /* start of DLE list */
  752.  
  753.     if (tag && ref) {               /* No wildcards */
  754.         if (isfirst) {              /* if not already found */
  755.             while (DLEp) {          /* go through list */
  756.                 for (i=0; i<DLEp->ddh.dds; i++) {       /* for all DDs */
  757.                     if (DLEp->dd[i].tag==tag &&
  758.                             DLEp->dd[i].ref==ref)
  759.                         {*cDLEp=DLEp; *cddp=i; return(0);}
  760.                     }
  761.                 DLEp=DLEp->next;
  762.                 }
  763.             }
  764.         }
  765.     else if (tag && !ref)           /* wildcard ref */
  766.         while (DLEp) {
  767.             for (i=0; i<DLEp->ddh.dds; i++) {
  768.                 wtag=DLEp->dd[i].tag;
  769.                 wref=DLEp->dd[i].ref;
  770.         /* condition = tag match, better than found so far (if any),
  771.             follows what was returned last time (if any) */
  772.                 if ( (wtag==tag) && (!found || (wref<cref)) &&
  773.                     (isfirst || (wref>lref)))
  774.                     { ctag=wtag; cref=wref; *cDLEp=DLEp; *cddp=i;found=1;}
  775.                 }
  776.             DLEp=DLEp->next;
  777.             }
  778.     else if (!tag && ref)           /* wildcard tag */
  779.         while (DLEp) {
  780.             for (i=0; i<DLEp->ddh.dds; i++) {
  781.                 wtag=DLEp->dd[i].tag;
  782.                 wref=DLEp->dd[i].ref;
  783.                 if ((wref==ref) && (isfirst || (wtag>ltag)) &&
  784.                     (!found || (wtag<ctag)) )
  785.                     { ctag=wtag; cref=wref; *cDLEp=DLEp; *cddp=i;found=1;}
  786.                 }
  787.             DLEp=DLEp->next;
  788.             }
  789.     else if (!tag && !ref)          /* wildcard tag & ref */
  790.         while (DLEp) {
  791.             for (i=0; i<DLEp->ddh.dds; i++) {
  792.                 wtag=DLEp->dd[i].tag;
  793.                 wref=DLEp->dd[i].ref;
  794.                 if ((isfirst || (wref>lref) || (wref==lref && wtag>ltag)) &&
  795.                     (!found || (wref<cref) || (wref==cref && wtag<ctag)) &&
  796.                     (wtag!=DFTAG_NULL))         /* empty DDs are invisible */
  797.                     { ctag=wtag; cref=wref; *cDLEp=DLEp; *cddp=i;found=1;}
  798.                 }
  799.             DLEp=DLEp->next;
  800.             }
  801.     return(found-1);            /* 0 or -1 */
  802. }
  803.  
  804.  
  805. /*-----------------------------------------------------------------------------
  806.  * Name:    DFIemptyDD
  807.  * Purpose: find an empty DD to use, or create a block of DDs if necessary
  808.  * Inputs:  dfile: pointer to open DF file
  809.  * Returns: pointer to an empty DD
  810.  * Invokes: DFIfind
  811.  * Users:   HDF system programmers, DFaccess, DFdup
  812.  *---------------------------------------------------------------------------*/
  813.  
  814. DFdd *DFIemptyDD(dfile)
  815. DF *dfile;
  816. {
  817.     DFdle *cDLEp;
  818.     int cdd;
  819.  
  820.     if (!DFIfind( dfile, DFTAG_NULL, DFREF_WILDCARD, 1, 0, 0, &cDLEp, &cdd))
  821.         return(&(cDLEp->dd[cdd]));      /* there is an empty DD */
  822.  
  823.     else {          /* add new DDH block */
  824.         int32 fpos;
  825.         DFdle *p, *dle;
  826.         DFddh ddh;
  827.         DFdd dd;
  828.         int j;
  829.  
  830.         CKSEEKEND( dfile->file, (long) 0, 2, NULL); /* go to end of df */
  831.         fpos= (int32) DF_TELL(dfile->file);
  832.         ddh.dds= dfile->defdds;             /* Initialize ddh */
  833.         ddh.next= 0;
  834.         dd.tag=DFTAG_NULL;                  /* and all DD's */
  835.         dd.ref=0;
  836. #ifdef DF_STRUCTOK
  837.         CKWRITE( &ddh, sizeof(DFddh), 1, dfile->file, NULL);
  838. #else /*DF_STRUCTOK*/
  839.         {
  840.             register  char *p;
  841.             p = DFtbuf;
  842.             INT16WRITE( p, ddh.dds);
  843.             INT32WRITE( p, ddh.next);
  844.             CKWRITE( DFtbuf, 6, 1, dfile->file, NULL);  /* 6 = size of header */
  845.         }
  846. #endif /*DF_STRUCTOK*/
  847.         for (j=0; j<ddh.dds; j++) {
  848. #ifdef DF_STRUCTOK
  849.             CKWRITE( &dd, sizeof(DFdd),1, dfile->file, NULL);
  850. #else /*DF_STRUCTOK*/
  851.             {
  852.                 register  char *p;
  853.                 p = DFtbuf;
  854.                 UINT16WRITE( p, dd.tag);
  855.                 UINT16WRITE( p, dd.tag);
  856.                 INT32WRITE( p, dd.offset);
  857.                 INT32WRITE( p, dd.length);
  858.                 CKWRITE( DFtbuf, 12, 1, dfile->file, NULL); /* 12=size of dd */
  859.             }
  860. #endif /*DF_STRUCTOK*/
  861.         }
  862.  
  863.         p=dfile->list;                      /* find end of list */
  864.         while (p->next) p= p->next;
  865.  
  866.         p->ddh.next=fpos;                   /* new dd goes at end of file */
  867.         dle=(DFdle *)
  868.         DFIgetspace((unsigned)
  869.             (sizeof(DFdle)+(ddh.dds-1)*sizeof(DFdd)));
  870.                             /* one dd included in dle */
  871.         CKMALLOC(dle, NULL);
  872.         p->next=dle;                        /* insert dle at end of list */
  873.         dle->next=NULL;
  874.         DFmovmem((char*)&ddh, (char*)&dle->ddh,sizeof(DFddh));
  875.         for (j=0; j<ddh.dds; j++)
  876.             DFmovmem( (char*)&dd, (char*)&dle->dd[j], sizeof(DFdd));
  877.         return(&(dle->dd[0]));
  878.     }
  879. #ifdef PC
  880.     return(NULL);           /* dummy, for return value checking */
  881. #endif /*PC*/
  882. }
  883.  
  884.  
  885. /*-----------------------------------------------------------------------------
  886.  * Name:    DFaccess
  887.  * Purpose: set up read/write access to a data element
  888.  * Inputs:  dfile: pointer to open DF file
  889.  *          tag, ref: id of element
  890.  *          access: "r", "w", "a" (append)
  891.  * Returns: 0 on success, -1 on failure
  892.  * Invokes: DFIcheck, DFIfind, DFIemptyDD
  893.  * Users:   HDF programmers, utilities, DFgetelement, DFputelement
  894.  * Remarks: if "a", data element will be copied to end of file, since it
  895.  *          cannot be extended in place if it is in the middle of the file
  896.  *---------------------------------------------------------------------------*/
  897.  
  898. int DFaccess(dfile, tag, ref, access)
  899. DF *dfile;
  900. uint16 tag, ref;
  901. char *access;
  902. {
  903.     DFdle *cDLEp;
  904.     int cdd;
  905.      char *storage=NULL;        /* for copying data if append access */
  906.     char accmode;
  907.     
  908.     DFerror = DFE_NOERROR;
  909.  
  910.     if (DFIcheck(dfile) )
  911.         return( -1);
  912.  
  913.     if (!tag) {
  914.         DFerror = DFE_BADTAG;
  915.         return(-1);
  916.     }
  917.     if (!ref) {
  918.         DFerror = DFE_BADREF;
  919.         return(-1);
  920.     }
  921.             /* set up and check access modes */
  922.     accmode = *access;
  923.     switch (accmode) {
  924.         case 'r':   dfile->up_access = DFACC_READ;  break;
  925.         case 'a':
  926.         case 'w':   dfile->up_access = DFACC_WRITE; break;
  927.         default:    DFerror = DFE_BADACC;   return(-1); 
  928.     }
  929.     if ((dfile->up_access & dfile->access) != dfile->up_access) {
  930.         DFerror = DFE_BADACC;
  931.         return(-1);
  932.     }
  933.                     
  934.                 /* Find DD of element to be updated */
  935.     if (!DFIfind( dfile, tag, ref, 1, 0 , 0, &cDLEp, &cdd))
  936.         dfile->up_dd = &(cDLEp->dd[cdd]);   /* DD of element to be updated */
  937.  
  938.     else {              /* No such DD */
  939.         if (accmode=='r') {
  940.             DFerror = DFE_NOMATCH; 
  941.             return(-1);
  942.         }
  943.         accmode = 'w';          /* append is really write if no current data */
  944.         dfile->up_dd = DFIemptyDD(dfile);       /* find an empty DD to use */
  945.         if (!dfile->up_dd) return(-1);
  946.         dfile->up_dd->tag = tag;                    /* fill in DD block */
  947.         dfile->up_dd->ref = ref;
  948.         dfile->up_dd->length = 0;
  949.     }
  950.  
  951.     if (accmode!='w') {        /*for read, DFaccess positions fp at element */
  952.                                 /* for append also, we need to read element */
  953.         CKSEEK(dfile->file, (long) dfile->up_dd->offset, 0, -1);
  954.         }
  955.     else dfile->up_dd->length = 0;  /* throws away any existing data */
  956.  
  957.     if (accmode!='r') {
  958.         dfile->changed = 1;         /* if write/append, file modified */
  959.  
  960.         if ((accmode=='a') && (dfile->up_dd->length)) {
  961.                     /* allocate storage to read current data */
  962.                 storage = (char*)DFIgetspace((unsigned)(dfile->up_dd->length));
  963.                 CKMALLOC( storage, -1 );
  964.                 CKREAD( storage, dfile->up_dd->length, 1, dfile->file, -1);
  965.         }
  966.  
  967.         CKSEEKEND( dfile->file, (long) 0, 2, -1);   /* go to end of df */
  968.             /* find the offset of the end of file */
  969.         dfile->up_dd->offset = (int32) DF_TELL(dfile->file);
  970.  
  971.         if ((accmode=='a') && dfile->up_dd->length) {   /* copy old data */
  972.             CKWRITE( storage, dfile->up_dd->length, 1, dfile->file, -1);
  973.                 /* note this leaves fp positioned correctly for write */
  974.         }
  975.         if (storage) DFIfreespace(storage);
  976.     }
  977.  
  978.     if (DFmaxref < ref) DFmaxref = ref;                 /* note ref is used */
  979.     if (DFreflist) DFreflist[ref/8] |= patterns[ref%8]; /* set ref'th bit */
  980.  
  981.     return(0);
  982. }
  983.  
  984.  
  985. /*-----------------------------------------------------------------------------
  986.  * Name:    DFstart
  987.  * Purpose: set up read/write access to a data element - alternate to DFaccess
  988.  * Inputs:  dfile: pointer to open DF file
  989.  *          tag, ref: id of element
  990.  *          access: "r", "w", "a" (append)
  991.  * Returns: 0 on success, -1 on failure
  992.  * Invokes: DFaccess
  993.  * Users:   Accidental/old-time users, intending to use DFaccess
  994.  * Remarks: none
  995.  *---------------------------------------------------------------------------*/
  996.  
  997. int DFstart(dfile, tag, ref, access)
  998. DF *dfile;
  999. uint16 tag, ref;
  1000. char *access;
  1001. {
  1002.  
  1003.     return(DFaccess(dfile, tag, ref, access));
  1004. }
  1005.         
  1006.  
  1007. /*-----------------------------------------------------------------------------
  1008.  * Name:    DFread
  1009.  * Purpose: read bytes from DF file (part of element specified by DFaccess)
  1010.  * Inputs:  dfile: pointer to open DF file
  1011.  *          ptr: pointer to space to read data into
  1012.  *          len: number of bytes to read
  1013.  * Returns: number of bytes read on success, -1 on failure
  1014.  * Invokes: DFIcheck
  1015.  * Users:   HDF programmers, DFgetelement
  1016.  *---------------------------------------------------------------------------*/
  1017.  
  1018. int32 DFread( dfile, ptr, len)
  1019. DF *dfile;
  1020. char *ptr;
  1021. int32 len;
  1022. {
  1023.     int32 maxlen;
  1024. #ifdef VMS
  1025.     int32 totalread;
  1026.     int32 readsize;
  1027. #endif /*VMS*/
  1028.  
  1029.     DFerror = DFE_NOERROR;
  1030.  
  1031.     if (DFIcheck(dfile) )
  1032.         return( (int32) -1);
  1033.  
  1034.     if (!dfile->up_dd) {
  1035.         DFerror = DFE_BADCALL;
  1036.         return((int32) -1);
  1037.     }
  1038.  
  1039.     if (!(dfile->up_access & DFACC_READ)) {
  1040.         DFerror = DFE_BADACC;
  1041.         return((int32) -1);
  1042.     }
  1043.  
  1044.     if (!ptr) {
  1045.         DFerror = DFE_BADPTR;
  1046.         return((int32) -1);
  1047.     }
  1048.  
  1049.     maxlen = dfile->up_dd->length -
  1050.                 ((int32) DF_TELL(dfile->file) - dfile->up_dd->offset);
  1051.     if (len>maxlen) len = maxlen;
  1052.     if (len<0) {            /* will also catch reads from beyond element */
  1053.         DFerror = DFE_BADLEN;
  1054.         return(-1);
  1055.     }
  1056.  
  1057. #ifdef VMS
  1058.     totalread = 0;
  1059.     while (totalread<len) {
  1060.         readsize = len - totalread;
  1061.         if (readsize>512) readsize = 512;
  1062.         CKREAD( &ptr[totalread], (int)readsize, 1, dfile->file, -1); 
  1063.         totalread += readsize;
  1064.     }
  1065.         
  1066. #else /*VMS*/
  1067.     if (len) {      /* NOTE: cast to (int) will limit to 64K on 16 bit m/cs */
  1068.         CKREAD( ptr, (int) len, 1, dfile->file, -1); 
  1069.     }
  1070. #endif /*VMS*/
  1071.  
  1072.     return(len);
  1073. }
  1074.  
  1075.  
  1076. /*-----------------------------------------------------------------------------
  1077.  * Name:    DFseek
  1078.  * Purpose: seek to a position, within element specified by DFaccess
  1079.  * Inputs:  dfile: pointer to open DF file
  1080.  *          offset: offset from beginning of element
  1081.  * Returns: offset of actual position seek'ed to from beginning of element
  1082.  * Invokes: DFIcheck
  1083.  * Users:   HDF programmers
  1084.  *---------------------------------------------------------------------------*/
  1085.  
  1086. int32 DFseek( dfile, offset)
  1087. DF *dfile;
  1088. int32 offset;
  1089. {
  1090.     
  1091.     DFerror = DFE_NOERROR;
  1092.  
  1093.     if (DFIcheck(dfile) )
  1094.         return( -1);
  1095.  
  1096.     if (!dfile->up_dd) {
  1097.         DFerror = DFE_BADCALL;
  1098.         return(-1);
  1099.     }
  1100.  
  1101.     if (!(dfile->up_access & DFACC_READ)) {
  1102.         DFerror = DFE_BADACC;
  1103.         return(-1);
  1104.     }
  1105.  
  1106.     if (offset > dfile->up_dd->length) {
  1107.         offset = dfile->up_dd->length;
  1108.         DFerror = DFE_BADSEEK;
  1109.     }
  1110.  
  1111.     CKSEEK( dfile->file, (long) dfile->up_dd->offset + offset, 0, -1);
  1112.     return(offset);
  1113. }
  1114.  
  1115.  
  1116. /*-----------------------------------------------------------------------------
  1117.  * Name:    DFwrite
  1118.  * Purpose: write bytes to DF file (part of element specified by DFaccess)
  1119.  * Inputs:  dfile: pointer to open DF file
  1120.  *          ptr: pointer to data to be written
  1121.  *          len: number of bytes to written
  1122.  * Returns: number of bytes written on success, -1 on failure
  1123.  * Invokes: DFIcheck
  1124.  * Users:   HDF programmers, DFputelement
  1125.  *---------------------------------------------------------------------------*/
  1126.  
  1127. int32 DFwrite( dfile, ptr, len)
  1128. DF *dfile;
  1129. char *ptr;
  1130. int32 len;
  1131. {
  1132. #ifdef VMS
  1133.     int32 totalwritten;
  1134.     int32 writesize;
  1135. #endif /*VMS*/
  1136.  
  1137.     DFerror = DFE_NOERROR;
  1138.  
  1139.     if (DFIcheck(dfile) )
  1140.         return( -1);
  1141.  
  1142.     if (!(dfile->up_dd)) {
  1143.         DFerror = DFE_BADCALL;
  1144.         return(-1);
  1145.     }
  1146.  
  1147.     if (!(dfile->up_access & DFACC_WRITE)) {
  1148.         DFerror = DFE_RDONLY;
  1149.         return(-1);
  1150.     }
  1151.  
  1152.     if (!ptr) {
  1153.         DFerror = DFE_BADPTR;
  1154.         return(-1);
  1155.     }
  1156.  
  1157.     if (len<0) {
  1158.         DFerror = DFE_BADLEN;
  1159.         return(-1);
  1160.     }
  1161.  
  1162.     if (!(dfile->changed)) {        /* if an update between writes, re-seek */
  1163.       CKSEEK( dfile->file, (long) dfile->up_dd->offset + dfile->up_dd->length,
  1164.             0, -1);
  1165.     }
  1166.  
  1167. #ifdef VMS
  1168.     totalwritten = 0;
  1169.     while (totalwritten<len) {
  1170.         writesize = len - totalwritten;
  1171.         if (writesize>512) writesize = 512; /* write at most 512 at a time */
  1172.         CKWRITE( &ptr[totalwritten], (int)writesize, 1, dfile->file, -1); 
  1173.         totalwritten += writesize;
  1174.     }
  1175. #else /*VMS*/
  1176.     if (len) { CKWRITE( ptr, len, 1, dfile->file, -1); }
  1177. #endif /*VMS*/
  1178.     dfile->up_dd->length += len;
  1179.     return(len);
  1180. }
  1181.  
  1182.  
  1183. /*-----------------------------------------------------------------------------
  1184.  * Name:    DFupdate
  1185.  * Purpose: write out updated DD blocks to file
  1186.  * Inputs:  dfile: pointer to open DF file
  1187.  * Returns: 0 on success, -1 on failure
  1188.  * Invokes: DFIcheck
  1189.  * Users:   HDF programmers
  1190.  *---------------------------------------------------------------------------*/
  1191.  
  1192. int DFupdate( dfile)
  1193. DF *dfile;
  1194. {
  1195.     DFdle *prev, *current;
  1196.     int i;
  1197.  
  1198.     DFerror = DFE_NOERROR;
  1199.  
  1200.     if ( DFIcheck(dfile))
  1201.         return(-1);
  1202.  
  1203.     if (dfile->type!=1) {
  1204.         DFerror= DFE_NOTOPEN;
  1205.         return(-1);
  1206.     }
  1207.  
  1208.     prev=dfile->list;           /* start of DLE list */
  1209.  
  1210.     if (dfile->changed) {           /* modified */
  1211.         while (current=prev->next) {
  1212.             CKSEEK( dfile->file, (long) prev->ddh.next,0, -1);
  1213.             if (current->ddh.dds) {
  1214. #ifdef DF_STRUCTOK
  1215.                 CKWRITE( ¤t->ddh, sizeof(DFddh) +
  1216.                     (current->ddh.dds*sizeof(DFdd)), 1, dfile->file, -1);
  1217. #else /*DF_STRUCTOK*/
  1218.                 {
  1219.                     register  char *p;
  1220.                     p = DFtbuf;
  1221.                     INT16WRITE( p, current->ddh.dds);
  1222.                     INT32WRITE( p, current->ddh.next);
  1223.                     for (i=0; i<current->ddh.dds; i++) {
  1224.                         UINT16WRITE( p, current->dd[i].tag);
  1225.                         UINT16WRITE( p, current->dd[i].ref);
  1226.                         INT32WRITE( p, current->dd[i].offset);
  1227.                         INT32WRITE( p, current->dd[i].length);
  1228.                     }
  1229.                     CKWRITE( DFtbuf, 6+i*12, 1, dfile->file, -1);
  1230.                         /* 6= size of DDH, 12=size of DD */
  1231.                 }
  1232. #endif /*DF_STRUCTOK*/
  1233.             }
  1234.             prev=current;
  1235.         }
  1236.         DF_FLUSH(dfile->file);              /* ensure everything is written */
  1237.     }
  1238.     dfile->changed=0;
  1239.     return(0);
  1240. }   
  1241.  
  1242.  
  1243. /*-----------------------------------------------------------------------------
  1244.  * Name:    DFstat
  1245.  * Purpose: provide status information about DF file
  1246.  * Inputs:  dfile: pointer to open DF file
  1247.  *          dfinfo: ptr to space where to place information on HDF file
  1248.  * Returns: 0 on success, -1 on failure
  1249.  * Invokes: DFIcheck
  1250.  * Users:   HDF programmers
  1251.  *---------------------------------------------------------------------------*/
  1252.  
  1253. int DFstat(dfile, dfinfo)
  1254. DF *dfile;
  1255. struct DFdata *dfinfo;
  1256. {
  1257.  
  1258.     DFerror = DFE_NOERROR;
  1259.  
  1260.     if (DFIcheck(dfile) )
  1261.         return( -1);
  1262.  
  1263.         /* This is version number of program.  More will be added later */
  1264.     dfinfo->version = DFVERSION;
  1265.     return(0);
  1266. }
  1267.     
  1268.  
  1269. /*-----------------------------------------------------------------------------
  1270.  * Name:    DFgetelement
  1271.  * Purpose: read a data element from df file
  1272.  * Inputs:  dfile: pointer to open DF file
  1273.  *          tag, ref: id of data element
  1274.  *          ptr: space to put data element in
  1275.  * Returns: number of bytes read on success, -1 on failure
  1276.  * Invokes: DFaccess, DFread
  1277.  * Users:   HDF programmers, utilities, many other routines
  1278.  *---------------------------------------------------------------------------*/
  1279.  
  1280. int32 DFgetelement( dfile, tag, ref, ptr)
  1281. DF *dfile;
  1282. uint16 tag, ref;
  1283. char *ptr;
  1284. {
  1285.     if ( DFaccess( dfile, tag, ref, "r")<0) return((int32) -1);
  1286.     return( DFread( dfile, ptr, (int32) dfile->up_dd->length));
  1287. }
  1288.  
  1289.  
  1290. /*-----------------------------------------------------------------------------
  1291.  * Name:    DFputelement
  1292.  * Purpose: write a data element to df file
  1293.  * Inputs:  dfile: pointer to open DF file
  1294.  *          tag, ref: id of data element
  1295.  *          ptr: pointer to data element to be written
  1296.  *          len: length of data element
  1297.  * Returns: 0 on success, -1 on failure
  1298.  * Invokes: DFaccess, DFwrite
  1299.  * Users:   HDF programmers, utilities, many other routines
  1300.  *---------------------------------------------------------------------------*/
  1301.  
  1302. int DFputelement( dfile, tag, ref, ptr, len)
  1303. DF *dfile;
  1304. uint16 tag, ref;
  1305.  char *ptr;
  1306. int32 len;
  1307. {
  1308.     if ( DFaccess( dfile, tag, ref, "w")<0) return(-1);
  1309.     if( DFwrite( dfile, ptr, len)<0) return(-1);
  1310.     return(0);
  1311. }
  1312.  
  1313.  
  1314. /*-----------------------------------------------------------------------------
  1315.  * Name:    DFdup
  1316.  * Purpose: Add a new tag/ref for existing data
  1317.  * Inputs:  dfile: pointer to open DF file
  1318.  *          itag, iref: new id of data element
  1319.  *          otag, oref: current id of data element
  1320.  * Returns: 0 on success, -1 on failure
  1321.  * Invokes: DFIcheck, DFIfind, DFIemptyDD
  1322.  * Users:   HDF programmers, utilities, many other routines
  1323.  *---------------------------------------------------------------------------*/
  1324.  
  1325. int DFdup(dfile, itag, iref, otag, oref)
  1326. DF *dfile;
  1327. uint16 itag, iref, otag, oref;  /* new, existing tag/refs */
  1328. {
  1329.     DFdle *odlep, *idlep;
  1330.     int ocdd, icdd;
  1331.     DFdd *newdd;
  1332.  
  1333.     DFerror = DFE_NOERROR;
  1334.  
  1335.     if (DFIcheck(dfile) )
  1336.         return( -1);
  1337.  
  1338.     if (DFIfind( dfile, otag, oref, 1, 0, 0, &odlep, &ocdd)<0) {
  1339.         DFerror = DFE_NOMATCH;      /* existing tag/ref does not exist! */
  1340.         return(-1);
  1341.     }
  1342.  
  1343.     if (!DFIfind( dfile, itag, iref, 1, 0, 0, &idlep, &icdd))
  1344.         newdd = &idlep->dd[icdd];   /* replaces existing DD */
  1345.     else {
  1346.         newdd = DFIemptyDD(dfile);  /* find empty DD */
  1347.         if (!newdd) return(-1);
  1348.         newdd->tag = itag;
  1349.         newdd->ref = iref;
  1350.  
  1351.         if (DFmaxref < iref) DFmaxref = iref;       /* mark iref as used */
  1352.         if (DFreflist) DFreflist[iref/8] |= patterns[iref%8];
  1353.     }
  1354.     newdd->offset = odlep->dd[ocdd].offset;
  1355.     newdd->length = odlep->dd[ocdd].length;
  1356.     dfile->changed = 1;
  1357.     return(0);
  1358. }
  1359.  
  1360.  
  1361. /*-----------------------------------------------------------------------------
  1362.  * Name:    DFdel
  1363.  * Purpose: Delete a data element from file
  1364.  * Inputs:  dfile: pointer to open DF file
  1365.  *          tag, ref: id of data element
  1366.  * Returns: 0 on success, -1 on failure
  1367.  * Invokes: DFIcheck, DFIfind
  1368.  * Users:   HDF programmers, utilities, many other routines
  1369.  * Remarks: Data element is not deleted, only the reference to it is changed
  1370.  *---------------------------------------------------------------------------*/
  1371.  
  1372. int DFdel(dfile, tag, ref)
  1373. DF *dfile;
  1374. uint16 tag, ref;
  1375. {
  1376.     DFdle *dlep;
  1377.     int cdd;
  1378.  
  1379.     DFerror = DFE_NOERROR;
  1380.  
  1381.     if (DFIcheck(dfile) )
  1382.         return( -1);
  1383.  
  1384.     if (DFIfind( dfile, tag, ref, 1, 0, 0, &dlep, &cdd)<0) {
  1385.         DFerror = DFE_NOMATCH;      /* nothing to delete */
  1386.         return(-1);
  1387.     }
  1388.     dlep->dd[cdd].tag = DFTAG_NULL;
  1389.     dlep->dd[cdd].ref = 0;
  1390.     dfile->changed = 1;
  1391.     return(0);
  1392. }
  1393.  
  1394.  
  1395. /*-----------------------------------------------------------------------------
  1396.  * Name:    DFnewref
  1397.  * Purpose: Get an ununsed reference number
  1398.  * Inputs:  dfile: pointer to HDF file
  1399.  *          tag: tag for which ref is needed
  1400.  * Returns: unused ref number if found.  0 with DFerror set if not.
  1401.  * Users:   HDF programmers, for adding data elements
  1402.  * Invokes: DFIcheck
  1403.  * Remarks: Currently, returns a ref which is not used with any tag, except
  1404.  *          possibly DFTAG_MT
  1405.  *---------------------------------------------------------------------------*/
  1406.  
  1407. uint16 DFnewref(dfile)
  1408. DF *dfile;
  1409. {
  1410.     DFdle *DLEp;
  1411.     int i,j;
  1412.  
  1413.     DFerror = DFE_NOERROR;
  1414.  
  1415.     if (DFIcheck(dfile) )
  1416.         return ((uint16) 0);
  1417.  
  1418.     if (DFmaxref < 65535)       /* 65535 = largest 16-bit uint = largest ref */
  1419.         return(++DFmaxref);
  1420.  
  1421.     /* allocate a bit array of 65536 bits - one for each ref */
  1422.     if (DFreflist==NULL) {
  1423.         if ((DFreflist = (unsigned char *) DFIgetspace(8192)) == NULL)
  1424.                 return((uint16) 0);             /* 8192 = 65536/8 */
  1425.         
  1426.         for (i=1; i<8192; i++) DFreflist[i] = 0;    /* initialize */
  1427.         DFreflist[0] = 0x80;            /* ref 0 is not to be allocated */
  1428.  
  1429.         for (DLEp=dfile->list; DLEp; DLEp=DLEp->next) /* go through all DDs */
  1430.             for (i=0; i<DLEp->ddh.dds; i++)
  1431.                 if (DLEp->dd[i].tag != DFTAG_MT)    /* set ref'th bit to 1 */
  1432.                     DFreflist[DLEp->dd[i].ref/8] |=
  1433.             patterns[DLEp->dd[i].ref%8];
  1434.     }
  1435.  
  1436.     for (i=0; i<8192; i++)
  1437.         if (DFreflist[i] != 0xff) break; /* if ff, all refs taken */
  1438.  
  1439.     if (i==8192) {
  1440.         DFerror = DFE_NOREF;
  1441.         return((uint16) 0);
  1442.     }
  1443.  
  1444.     for (j=0; j<8; j++) {
  1445.         if (!(DFreflist[i] & patterns[j])) { /* ref j is not allocated */
  1446.             DFreflist[i] |= patterns[j]; /* ref j is now in use */
  1447.             return((uint16) (i*8 + j));    /* ref to use */
  1448.         }
  1449.     }
  1450.  
  1451.     return((uint16) 0);        /* this statement should not be reached */
  1452. }
  1453.  
  1454.  
  1455. /*-----------------------------------------------------------------------------
  1456.  * Name:    DFishdf
  1457.  * Purpose: Is this an HDF file?
  1458.  * Inputs:  filename: name of HDF file
  1459.  * Returns: 0 if it is an HDF file, -1 if not.  DFerror is set to open error
  1460.  *              if any, else to DFE_NOERROR
  1461.  * Users:   HDF systems programmers, for checking files
  1462.  * Invokes: DFopen, DFclose
  1463.  * Remarks: none
  1464.  *---------------------------------------------------------------------------*/
  1465.  
  1466. DFishdf(filename)
  1467. char *filename;
  1468. {
  1469.     DF *dfile;
  1470.  
  1471.     DFerror = DFE_NOERROR;
  1472.  
  1473.     dfile = DFopen(filename, DFACC_READ, -1);
  1474.     if (dfile==NULL) return(-1);
  1475.     return(DFclose(dfile));
  1476. }
  1477.  
  1478.  
  1479. /*-----------------------------------------------------------------------------
  1480.  * Name:    DFerrno
  1481.  * Purpose: return value of DFerror
  1482.  * Inputs:  none
  1483.  * Returns: value of DFerror
  1484.  * Users:   HDF users, programmers
  1485.  * Invokes: none
  1486.  * Remarks: none
  1487.  *---------------------------------------------------------------------------*/
  1488.  
  1489. int DFerrno()
  1490. {
  1491.  
  1492.     return(DFerror);
  1493. }
  1494.  
  1495.  
  1496. /*-----------------------------------------------------------------------------
  1497.  * Name:    DFIerr
  1498.  * Purpose: Close a file and return on error. save DFerror
  1499.  * Inputs:  dfile: pointer to HDF file to close
  1500.  * Returns: -1
  1501.  * Users:   HDF systems programmers, for error handling
  1502.  * Invokes: DFclose
  1503.  * Remarks: Used to centralize some error handling
  1504.  *---------------------------------------------------------------------------*/
  1505.  
  1506. int DFIerr(dfile)
  1507. DF *dfile;
  1508. {
  1509.     int saveerror;
  1510.  
  1511.     saveerror = DFerror;
  1512.     if (dfile!=NULL) (void) DFclose(dfile);
  1513.     DFerror = saveerror;
  1514.     return(-1);
  1515. }
  1516.